/* RPCTranslator.cc -- Tradutor das mensagens recebidas e enviadas.
 *
 * Copyright (C) 2008, Diogo F. S. Ramos <diogo.ramos@usp.br>
 * GEAR - Grupo de Estudos Avançados em Robótica
 * <http://www.sel.eesc.usp.br/gear>
 *
 * This file is part of GEARMedula.
 * 
 * GEARMedula is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation, version 3 of the License.
 * 
 * GEARMedula is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see
 * <http://www.gnu.org/licenses/>.
 */

#include "RPCTranslator.hh"
#include "Messages.hh"
#include "Fields.hh"
#include "FieldInterface.hh"
#include "MessageInterface.hh"


RPCTranslator::RPCTranslator(void)
{
    PopulateFieldTableDecode();
    PopulateFieldTableEncode();
    PopulateMessageTable();

}

void
RPCTranslator::Init( char * incoming_buffer,
                     char * outgoing_buffer )
{

    incoming_buffer_ = incoming_buffer;
    outgoing_buffer_ = outgoing_buffer;
    
    xdrmem_create( &xdrs_incoming_,
                   incoming_buffer_,
                   kBufferSize,
                   XDR_DECODE );

    xdrmem_create( &xdrs_outgoing_,
                   outgoing_buffer_,
                   kBufferSize,
                   XDR_ENCODE );

}

int
RPCTranslator::Receive( MessageType *message_type,
                        std::vector< struct FieldContainer> &arguments_received,
                        RPCSide rpc_side)
{
    switch( rpc_side )
    {
    case RPCSIDE_CLIENT:
    {
        // Descobrir qual é o ID da mensagem
        int message_ID = 4;
        xdr_int( &xdrs_incoming_,
                 &message_ID );                               
        *message_type = (MessageType) message_ID;
        
        const FieldType * message_field_table_of_sent =
            message_table_[*message_type]->getFieldTableOfReturned();
        
        int field_index = 0;
        int number_of_parameters =
            message_table_[*message_type]->getNumberOfParametersToReturn();
        arguments_received.resize( number_of_parameters );
        while( field_index < number_of_parameters )
        {
            FieldType field_type = message_field_table_of_sent[field_index];
            field_table_decode_[field_type]->ParseField( &xdrs_incoming_,
                                                         &(arguments_received[field_index]) );
            field_index++;
        }

        break;
    }
    case RPCSIDE_SERVER:
    {
        // Descobrir qual é o ID da mensagem
        int message_ID = 4;
        xdr_int( &xdrs_incoming_,
                 &message_ID );                               
        *message_type = (MessageType) message_ID;
        
        const FieldType * message_field_table_of_sent =
            message_table_[*message_type]->getFieldTableOfSent();
        
        int field_index = 0;
        int number_of_parameters =
            message_table_[*message_type]->getNumberOfParametersToSend();
        arguments_received.resize( number_of_parameters );
        while( field_index < number_of_parameters )
        {
            FieldType field_type = message_field_table_of_sent[field_index];
            field_table_decode_[field_type]->ParseField( &xdrs_incoming_,
                                                         &(arguments_received[field_index]) );
            field_index++;
        }

        break;
    }
    default:
    {
        break;
    }
    }

    ResetReceivedMessage();
    
    return 0;
}

int
RPCTranslator::Send( const MessageType message_type,
                     std::vector< struct FieldContainer> arguments_sent,
                     RPCSide rpc_side )
{
    switch( rpc_side )
    {
    case RPCSIDE_CLIENT:
    {
        setMessageType( message_type );
        
        const FieldType * message_field_table_of_sent =
            message_table_[message_type]->getFieldTableOfSent();
        
        int field_index = 0;
        int number_of_parameters =
            message_table_[message_type]->getNumberOfParametersToSend();
        while( field_index < number_of_parameters )
        {
            FieldType field_type = message_field_table_of_sent[field_index];
            field_table_encode_[field_type]->ParseField( &xdrs_outgoing_,
                                                         &(arguments_sent[field_index]) );
            field_index++;
        }
        break;
    }
    case RPCSIDE_SERVER:
    {
        setMessageType( message_type );

        const FieldType * message_field_table_of_sent =
            message_table_[message_type]->getFieldTableOfReturned();

        int field_index = 0;
        int number_of_parameters =
            message_table_[message_type]->getNumberOfParametersToReturn();
        while( field_index < number_of_parameters )
        {
            FieldType field_type = message_field_table_of_sent[field_index];
            field_table_encode_[field_type]->ParseField( &xdrs_outgoing_,
                                                         &(arguments_sent[field_index]) );
            field_index++;
        }
        break;
    }
    default:
        break;
    }

    ResetSentMessage();

    return 0;
}


void
RPCTranslator::setMessageType( MessageType message_type )
{
    xdr_int( &xdrs_outgoing_,
             (int*) &message_type );
}


int
RPCTranslator::ResetSentMessage()
{
    return xdr_setpos( &xdrs_outgoing_,
                       0 );

}

int
RPCTranslator::ResetReceivedMessage()
{
    return xdr_setpos( &xdrs_incoming_,
                       0 );

}


int
RPCTranslator::getMessageNumberOfParametersToSend( MessageType message_type )
{
    
    return message_table_[MESSAGETYPE_SET_VEL]->getNumberOfParametersToSend();
}


void
RPCTranslator::PopulateFieldTableDecode()
{
    field_table_decode_[FIELDTYPE_FLOAT] = new FloatField( FIELDOPERATION_DECODE );
    field_table_decode_[FIELDTYPE_INTEGER] = new IntegerField( FIELDOPERATION_DECODE );
    field_table_decode_[FIELDTYPE_FIELD_VECTOR] = new FieldVectorField( FIELDOPERATION_DECODE );
    field_table_decode_[FIELDTYPE_WORLD_VECTOR] = new WorldVectorField( FIELDOPERATION_DECODE );
    field_table_decode_[FIELDTYPE_STRING] = new StringField( FIELDOPERATION_DECODE );
}

void
RPCTranslator::PopulateFieldTableEncode()
{
    field_table_encode_[FIELDTYPE_FLOAT] = new FloatField( FIELDOPERATION_ENCODE );
    field_table_encode_[FIELDTYPE_INTEGER] = new IntegerField( FIELDOPERATION_ENCODE );
    field_table_encode_[FIELDTYPE_FIELD_VECTOR] = new FieldVectorField( FIELDOPERATION_ENCODE );
    field_table_encode_[FIELDTYPE_WORLD_VECTOR] = new WorldVectorField( FIELDOPERATION_ENCODE );
    field_table_encode_[FIELDTYPE_STRING] = new StringField( FIELDOPERATION_ENCODE );
}

void
RPCTranslator::PopulateMessageTable()
{
    message_table_[MESSAGETYPE_SAY_HELLO] = new SayHelloMessage();
    message_table_[MESSAGETYPE_SET_VEL] = new SetVelMessage();
    message_table_[MESSAGETYPE_GET_FIELD] = new GetFieldMessage();
    message_table_[MESSAGETYPE_SET_FIELD] = new SetFieldMessage();
    message_table_[MESSAGETYPE_GET_WORLD] = new GetWorldMessage();
    message_table_[MESSAGETYPE_SET_WORLD] = new SetWorldMessage();
    message_table_[MESSAGETYPE_KICK] = new KickMessage();
    message_table_[MESSAGETYPE_DRIBBLE_ENABLE] = new DribbleEnableMessage();
    message_table_[MESSAGETYPE_REGISTER_ROBOT_NAME] = new RegisterRobotNameMessage();
}
